/******************************************************************************
 *      Mestrado em Ciência da Computação - UFMS
 *		Redes de Computadores - Prof. Dr. Ronaldo Alves Ferreira
 *		Alunos: Geraldo Landre, Marcel Tolentino, Vinícius Bueno
 *****************************************************************************/

#ifndef REQUEST_H
#define REQUEST_H

#include "vstring.h"


#include "base.h"
#include "config.h"
#include "cache.h"

#define BUFFER		1024

#define CR "\r"
#define CRLF "\r\n" // só \n para que o strtok funcione
#define SPACE " "

#define HTTP_VERSION "HTTP/1.1"

#define STR_GET		"GET"
#define STR_HEAD	"HEAD"
#define STR_POST	"POST"
#define STR_PUT		"PUT"
#define STR_DELETE	"DELETE"
#define STR_TRACE	"TRACE"
#define STR_CONNECT	"CONNECT"

#define URI_MAX_LEN		256		// tamanho máximo de dir/file UNIX

/*	Erros HTTP	*/
typedef enum
{
    MSG_CONTINUE =                              100,
    MSG_SWITCHING_PROTOCOLS =                   101,
    MSG_OK =                                    200,
    MSG_CREATED =                               201,
    MSG_ACCEPTED =                              202,
    MSG_NON_AUTHORITATIVE_INFORMATION =         203,
    MSG_NO_CONTENT =                            204,
    MSG_RESET_CONTENT =                         205,
    MSG_PARTIAL_CONTENT =                       206,
    ERR_MULTIPLE_CHOICES =                      300,
    ERR_MOVED_PERMANENTLY =                     301,
    ERR_FOUND =                                 302,
    ERR_SEE_OTHER =                             303,
    ERR_NOT_MODIFIED =                          304,
    ERR_USE_PROXY =                             305,
    ERR_TEMPORARY_REDIRECT =                    307,
    ERR_BAD_REQUEST =                           400,
    ERR_UNAUTHORIZED =                          401,
    ERR_PAYMENT_REQUIRED =                      402,
    ERR_FORBIDDEN =                             403,
    ERR_NOT_FOUND =                             404,
    ERR_METHOD_NOT_ALLOWED =                    405,
    ERR_NOT_ACCEPTABLE =                        406,
    ERR_PROXY_AUTHENTICATION_REQUIRED =         407,
    ERR_REQUEST_TIME_OUT =                      408,
    ERR_CONFLICT =                              409,
    ERR_GONE =                                  410,
    ERR_LENGTH_REQUIRED =                       411,
    ERR_PRECONDITION_FAILED =                   412,
    ERR_REQUEST_ENTITY_TOO_LARGE =              413,
    ERR_REQUEST_URI_TOO_LARGE =                 414,
    ERR_UNSUPPORTED_MEDIA_TYPE =                415,
    ERR_REQUESTED_RANGE_NOT_SATISFIABLE =       416,
    ERR_EXPECTATION_FAILED =                    417,
    ERR_INTERNAL_SERVER_ERROR =                 500,    
    ERR_NOT_IMPLEMENTED =                       501,
    ERR_BAD_GATEWAY =                           502,
    ERR_SERVICE_UNAVAILABLE =                   503,
    ERR_GATEWAY_TIME_OUT =                      504,
    ERR_HTTP_VERSION_NOT_SUPPORTED =            505

/*
| "416" ; Section 10.4.17: Requested range not satisfiable
| "417" ; Section 10.4.18: Expectation Failed
| "502" ; Section 10.5.3: Bad Gateway
| "504" ; Section 10.5.5: Gateway Time-out*/

} HTTP_ERROR;

typedef struct
{
    // valores referentes ao controle da cache (passados pelo Cache-Control)
    int is_public; // será 1 se público ou 0 se privado
    int no_cache;
    int no_store;
    int max_age;
    int max_stale;
    int min_fresh;
    int no_transform;
    int only_if_cached;
    int must_revalidate;
    int proxy_revalidate;
    int s_maxage;
    vstring *cache_extension;
    vstring *field_name;
}cache_control;

typedef struct
{
    // "booleano" para identificar se o cabeçalho é de uma requisição de cliente
    //ou mensagem de resposta de outro servidor
    int last_irc;
    int client_socket;
    int is_response;
    int end;  // indicador de que o header acabou (contar quantos enters chegou)
    int alive; // indicador de conexão persistente
    int error; // código do status da resposta
    int method; // código do método do cabeçalho
    int chunked; // indicador para dizer se o parâmetro chunked veio no Transfer-Encoding

    vstring* method_str; // guardar o metodo em forma de string (gg)
    vstring* http; // versão http
    vstring* port; // porta utilizada
    vstring* request; // requisição recebida/enviada
    vstring* msg; // corpo do pacote
    vstring* host; // host

    vstring* srv_url; // url do servidor de origem
    vstring* srv_port;
    vstring* srv_request;

    int age;
    int allow[8]; // vetor "booleano" para indicar cada método suportado pelo cliente

    cache_control *cache_params; // ponteiro pois se não houver Cache-Control não precisa alocar

    int content_length;
    vstring *content_location;
    struct tm *date;
    struct tm *expires;

    vstring **header;
}header_data;

cache_control* new_cache_control();

void print_cache_control(cache_control *cc);

header_data* new_header();

void reset_header(header_data **hd);

void copy_header_data(header_data **oldhd,header_data **newhd);

int is_empty(header_data *hd);

void print_header_data(const header_data *hd);

/*	Verifica o erro na variável global 'httperr' e retorna
	a mensagem correspondente	*/
char* get_str_httperror(int error);

int is_cacheable(header_data *hd);

int is_finished(header_data *hd);

#endif
